﻿using CSRedis;
using Dapper;
using Himp.TaskScheduling.Hangfire.Jobs;
using Himp.TaskScheduling.Hangfire.Models;
using Microsoft.AspNetCore.DataProtection.KeyManagement;
using Microsoft.Data.SqlClient;
using Microsoft.Extensions.Options;
using System.Data;
using static Hangfire.Storage.JobStorageFeatures;

namespace Himp.TaskScheduling.Hangfire
{
    /// <summary>
    /// 温湿度
    /// </summary>
    public class TempHumJob : IHostedService, IDisposable
    {
        #region SQL

        public const string INSERT_HY_WARMHUMID_SQL = @"
            INSERT INTO
            HY_Warmhumid
            (
            LaboratoryId,
            Temperature,
            Humidity,
            BeginTime,
            EndTime,
            UserName
            )
            VALUES
            (
            @LaboratoryId,
            @Temperature,
            @Humidity,
            @BeginTime,
            @EndTime,
            @UserName
            )";

        public const string EXIST_HY_WARMHUMID_SQL = @"
            SELECT COUNT(*)
            FROM HY_Warmhumid
            WHERE LaboratoryId=@LaboratoryId 
            AND EndTime<=@EndTime
            ";

        public const string INSERT_EVENTMSGREC_RECORD = @"
            INSERT INTO
            [TaskScheduling].[TS_EventMsgRec]
            (
            Id,
            TopicFullPath,
            MsgTopicName,
            MsgCont,
            EventMsgOperStas,
            CreationTime,
            ExtraProperties,
            ConcurrencyStamp
            )
            VALUES
            (
            @Id,
            @TopicFullPath,
            @MsgTopicName,
            @MsgCont,
            @EventMsgOperStas,
            @CreationTime,
            @ExtraProperties,
            @ConcurrencyStamp
            )
            ";

        #endregion

        #region 字段

        private CSRedisClient _client;
        private Timer _timer;
        private readonly TimeSpan _interval = TimeSpan.FromMilliseconds(60000);
        private readonly TimeSpan _delay = TimeSpan.FromMilliseconds(0);
        private bool _isExecuting = false;
        private static readonly object _lock = new object();
        private bool _init = false;
        private ILogger<TempHumJob> _logger;
        private readonly ConnectionStringOption _connectionStrings;

        #endregion

        #region 方法

        public TempHumJob(ILogger<TempHumJob> logger
            , IOptions<ConnectionStringOption> connectionStrings)
        {
            _connectionStrings = connectionStrings.Value;
            _logger = logger;
            // 初始化计时器，初始时不启动，等待 StartAsync 启动
            _timer = new Timer(ExecuteJob, null, _delay, Timeout.InfiniteTimeSpan);
            _client = new CSRedis.CSRedisClient(_connectionStrings.KaiYRedis);
            RedisHelper.Initialization(_client);
            _init = true;
        }

        private async void ExecuteJob(object state)
        {
            if (_isExecuting || !_init)
            {
                // 如果任务正在执行，则跳过
                return;
            }

            lock (_lock)
            {
                if (_isExecuting)
                {
                    return;
                }
                _isExecuting = true;
            }

            try
            {
                // 你的任务逻辑
                await RunAsync();

            }
            catch (Exception e)
            {
                await Console.Out.WriteLineAsync(e.Message);
            }
            finally
            {
                GC.Collect(0);
                lock (_lock)
                {
                    _isExecuting = false;
                }
                // 任务完成后重新设置计时器
                _timer.Change(_interval, Timeout.InfiniteTimeSpan);
            }
        }

        private async Task RunAsync()
        {
            var matTemp = await RedisHelper.GetAsync("MAT1:SQL1:总控状态_当前设备内温度:Value");
            var matTempStamp = await RedisHelper.GetAsync("MAT1:SQL1:总控状态_当前设备内温度:Stamp");
            var matHum = await RedisHelper.GetAsync("MAT1:SQL1:总控状态_当前设备内湿度:Value");
            var matHumStamp = await RedisHelper.GetAsync("MAT1:SQL1:总控状态_当前设备内湿度:Stamp");

            var rilsTemp = await RedisHelper.GetAsync("RILS:SQL1:常温区_温度:Value");
            var rilsTempStamp = await RedisHelper.GetAsync("RILS:SQL1:常温区_温度:Stamp");
            var rilsHum = await RedisHelper.GetAsync("RILS:SQL1:常温区_湿度:Value");
            var rilsHumStamp = await RedisHelper.GetAsync("RILS:SQL1:常温区_湿度:Stamp");

            var matTempTime = DateTime.Parse(matTempStamp);
            var rilsTempTime = DateTime.Parse(rilsTempStamp);

            HY_Warmhumid mat =new HY_Warmhumid();
            mat.LaboratoryId = 1;
            mat.Humidity = decimal.Parse(matHum) / (decimal)10.0;
            mat.Temperature = decimal.Parse(matTemp) / (decimal)10.0;
            mat.BeginTime = matTempTime;
            mat.EndTime = matTempTime;
            mat.UserName = "自动";

            HY_Warmhumid rils = new HY_Warmhumid();
            rils.LaboratoryId = 2;
            rils.Humidity = decimal.Parse(rilsHum);
            rils.Temperature = decimal.Parse(rilsTemp);
            rils.BeginTime = rilsTempTime;
            rils.EndTime = rilsTempTime;
            rils.UserName = "自动";

            using (IDbConnection connection = new SqlConnection(_connectionStrings.RL_Web))
            {
                var existMat = connection.ExecuteScalar<int>(EXIST_HY_WARMHUMID_SQL, mat);

                if (existMat == 0)
                {
                    var insertMatStas = await connection.ExecuteAsync(INSERT_HY_WARMHUMID_SQL, mat);
                }

                var existRils = connection.ExecuteScalar<int>(EXIST_HY_WARMHUMID_SQL, rils);

                if (existRils == 0)
                {
                    var insertRilsStas = await connection.ExecuteAsync(INSERT_HY_WARMHUMID_SQL, rils);
                }
            }
        }

        public Task StartAsync(CancellationToken cancellationToken)
        {
            _timer.Change(_delay, _interval);
            return Task.CompletedTask;
        }

        public Task StopAsync(CancellationToken cancellationToken)
        {
            _timer?.Dispose();
            return Task.CompletedTask;
        }

        public void Dispose()
        {
            _timer?.Dispose();
        }

        #endregion
    }
}
